

const curry = require('lodash.curry');
const shouldThrow404 = (status, body) => {
  return !status || (status === 404 && body == null);
};

const shouldEmitError = (err, status) => {
  return !err.expose && status >= 500;
};

const toErrorObject = curry((err, acum, propertyName) => {
  return err[propertyName] ? Object.assign({}, acum, {
    [propertyName]: err[propertyName]
  }) : acum;
});


const DEFAULT_PROPERTIES = [
  'name',
  'message',
  'type'
];

const gatherData = (err, status) => {
  // if(process.env.NODE_ENV !== 'production'){
  //   DEFAULT_PROPERTIES.push('stack');
  // }
  const formattedError = DEFAULT_PROPERTIES.reduce(toErrorObject(err), {});
  return {
    ...formattedError,
    status
  };
}


module.exports = () => {

  let MyErr = true;
  let MyStatus = 200;

  return function jsonError(ctx, next) {

    ctx._throw = (status, msg) => {
      MyStatus = status;
      MyErr = false;
      ctx.throw(200, msg);
    };//重新方法

    return next()
      .then(() => {
        // future proof status
        shouldThrow404(ctx.status, ctx.body) && ctx.throw(404);
      })
      .catch((err, data) => {
        // Format and set body
        if (MyErr) {
          ctx.body = gatherData(err, err.status||404);
          ylog.error(`system error: ${err.message}`);
          
        }else {
          ctx.body = gatherData(err, MyStatus || 404);
        }
        
        // Set status
        ctx.status = err.status || err.statusCode || 500;
        // Emit the error if we really care
        shouldEmitError(err, ctx.status) && ctx.app.emit('error', err, ctx);
        MyErr = true;
      });
  };
};